<?php
/**
 * This file defines the {@see \BF\Drawing\Point} class.
 *
 * @author     Kado <ulfikado@gmail.com>
 * @category   Beluga PHP5.3+ Framework
 * @package    BF\Drawing
 * @since      2015-01-31 00:29
 * @subpackage Core
 * @version    0.1
 */

namespace BF\Drawing
{

   /**
    * This class defines a 2 dimensional point.
    *
    * @since      v1.0.0
    */
   class Point
   {

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   F I E L D S   - - - - - - - - - - - - - - - - - - - - - - -">

      /**
       * The X coordinate (horizontal)
       *
       * @var integer
       */
      public $X;

      /**
       * The Y coordinate (vertical)
       *
       * @var integer
       */
      public $Y;

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - >   P U B L I C   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - -">

      /**
       * Inits a new instance.
       *
       * @param integer $x  The X coordinate (horizontal)
       * @param integer $y  The Y coordinate (vertical)
       */
      public function __construct( $x = 0, $y = 0 )
      {
          $this->X = $x;
          $this->Y = $y;
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   M E T H O D S   - - - - - - - - - - - - - - - - - - - - - -">

      /**
       * Returns if X and Y is 0.
       *
       * @return boolean
       */
      public final function isEmpty()
      {
         return $this->X === 0 && $this->Y === 0;
      }

      /**
       * Writes the current instance data as XML element to a XmlWriter.
       *
       * The resulting XML element looks like follow:
       *
       * <b>&lt;Point x="0" y="0"/&gt;</b>
       *
       * @param \XMLWriter $w           The XmlWriter.
       * @param string     $elementName The name of the XMLelement to write (default='Point')
       *                                If no usable element name is defined, only the attributes are written!
       */
      public function writeXml( \XMLWriter $w, $elementName = 'Point' )
      {
         $writeElement = ! empty( $elementName );
         if ( $writeElement )
         {
            $w->startElement( $elementName );
         }
         $this->writeXmlAttributes( $w );
         if ( $writeElement )
         {
            $w->endElement();
         }
      }

      /**
       * Write the current instance data as XML element attributes to defined XmlWriter.
       *
       * @param  \XMLWriter $w The XmlWriter.
       */
      public function writeXmlAttributes( \XMLWriter $w )
      {
         $w->writeAttribute( 'x', $this->X );
         $w->writeAttribute( 'y', $this->Y );
      }

      /**
       * @return string
       */
      public function __toString()
      {
         return \sprintf( 'x=%d; y=%d', $this->X, $this->Y );
      }

      /**
       * @return array
       */
      public function toArray()
      {

         return array(
            'x' => $this->X,
            'y' => $this->Y
         );

      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   S T A T I C   M E T H O D S   - - - - - - - - - - - - - - -">

      /**
       * Inits a new {@see \BF\Drawing\Point} instance from defined XML element and returns it.
       *
       * @param  \SimpleXMLElement $element The XML element, defining the point data by 2 attributes 'x' + 'y'.
       * @return \BF\Drawing\Point Returns the resulting point, or boolean FALSE if no usable data are defined.
       */
      public static function FromXml( \SimpleXMLElement $element )
      {

         // Getting X
         $x = null;
         if ( isset( $element[ 'x' ] ) )
         {
            $x = \intval( $element[ 'x' ] );
         }
         elseif ( isset( $element[ 'X' ] ) )
         {
            $x = \intval( $element[ 'X' ] );
         }
         elseif ( isset( $element[ 'attributes' ][ 'x' ] ) )
         {
            $x = \intval( $element[ 'attributes' ][ 'x' ] );
         }
         elseif ( isset( $element[ 'attributes' ][ 'X' ] ) )
         {
            $x = \intval( $element[ 'attributes' ][ 'X' ] );
         }
         elseif ( isset( $element[ '@attributes' ][ 'x' ] ) )
         {
            $x = \intval( $element[ '@attributes' ][ 'x' ] );
         }
         elseif ( isset( $element[ '@attributes' ][ 'X' ] ) )
         {
            $x = \intval( $element[ '@attributes' ][ 'X' ] );
         }

         // Getting Y
         $y = null;
         if ( isset( $element[ 'y' ] ) )
         {
            $y = \intval( $element[ 'y' ] );
         }
         elseif ( isset( $element[ 'Y' ] ) )
         {
            $y = \intval( $element[ 'Y' ] );
         }
         elseif ( isset( $element[ 'attributes' ][ 'y' ] ) )
         {
            $y = \intval( $element[ 'attributes' ][ 'y' ] );
         }
         elseif ( isset( $element[ 'attributes' ][ 'Y' ] ) )
         {
            $y = \intval( $element[ 'attributes' ][ 'Y' ] );
         }
         elseif ( isset( $element[ '@attributes' ][ 'y' ] ) )
         {
            $y = \intval( $element[ '@attributes' ][ 'y' ] );
         }
         elseif ( isset( $element[ '@attributes' ][ 'Y' ] ) )
         {
            $y = \intval( $element[ '@attributes' ][ 'Y' ] );
         }

         if ( \is_null( $x ) || \is_null( $y ) )
         {
            return false;
         }

         return new \BF\Drawing\Point( $x, $y );

      }

      /**
       * Parst einen Wert und erstellt daraus eine neue \OSF\Drawing\Point-Instanz.
       * Wenn ein ungueltiges Format vorliegt wird (bool)FALSE zurück gegeben.
       *
       * @param  \OSF\Drawing\Point|\OSF\Drawing\Rectangle|string|array|\SimpleXMLElement $value Zu parsender Wert
       * @param  \OSF\Drawing\Point &$output
       * @return bool
       */
      public static function TryParse( $value, &$output )
      {
         if ( \is_null( $value ) )
         {
            return false;
         }
         if ( $value instanceof \BF\Drawing\Point )
         {
            $output = $value;
            return true;
         }
         if ( $value instanceof \BF\Drawing\Rectangle )
         {
            $output = $value->Point;
            return true;
         }
         if ( \is_string( $value ) )
         {
            $hits = null;
            if ( \preg_match( '~^x=(\d{1,4});\s*y=(\d{1,4})$~', $value, $hits ) )
            {
               $output = new \BF\Drawing\Point( \intval( $hits[ 1 ] ), \intval( $hits[ 2 ] ) );
               return true;
            }
            return false;
         }
         if ( \is_array( $value ) )
         {
            if ( isset( $value[ 'x' ] ) && isset( $value[ 'y' ] ) )
            {
               $output = new \BF\Drawing\Point( \intval( $value[ 'x' ] ), \intval( $value[ 'y' ] ) );
               return true;
            }
            if ( isset( $value[ 'X' ] ) && isset( $value[ 'Y' ] ) )
            {
               $output = new \BF\Drawing\Point( \intval( $value[ 'X' ] ), \intval( $value[ 'Y' ] ) );
               return true;
            }
            if ( \count( $value ) != 2 )
            {
               return false;
            }
            if ( isset( $value[ 0 ] ) && isset( $value[ 1 ] ) )
            {
               $output = new \BF\Drawing\Point( \intval( $value[ 0 ] ), \intval( $value[ 1 ] ) );
               return true;
            }
            return false;
         }
         if ( $value instanceof \SimpleXMLElement )
         {
            $output = self::FromXml( $value );
            return ( $output instanceof \BF\Drawing\Point );
         }
         $type = new \BF\Type( $value );
         if ( $type->hasAssociatedString() )
         {
            $hits = null;
            if ( \preg_match( '~^x=(\d{1,4});\s*y=(\d{1,4})$~', $type->getStringValue(), $hits ) )
            {
               $output = new \BF\Drawing\Point( \intval( $hits[ 1 ] ), \intval( $hits[ 2 ] ) );
               return true;
            }
         }
         return false;
      }

      # </editor-fold>

   }

}

